package com.sagacity.framework.feign.slf4j;

import com.sagacity.framework.util.StringUtil;
import feign.Request;
import feign.Response;
import feign.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

import static feign.Util.*;

/**
 * 自定义Feign日志方法
 */
public class FeignSlf4jLogger extends feign.Logger {

    private final Logger logger;

    public FeignSlf4jLogger() {
        this(feign.Logger.class);
    }

    public FeignSlf4jLogger(Class<?> clazz) {
        this(LoggerFactory.getLogger(clazz));
    }

    public FeignSlf4jLogger(String name) {
        this(LoggerFactory.getLogger(name));
    }

    FeignSlf4jLogger(Logger logger) {
        this.logger = logger;
    }

    @Override
    protected void logRequest(String configKey, Level logLevel, Request request) {
        if (logger.isDebugEnabled()) {
            feignLogRequest(configKey, logLevel, request);
        }
    }

    private void feignLogRequest(String configKey, Level logLevel, Request request) {
        if (logLevel.ordinal() == Level.FULL.ordinal()) {
            int bodyLength;
            if (request.body() != null) {
                bodyLength = request.length();
                if (bodyLength > 0) {
                    String bodyText;
                    if(bodyLength < 1024*1024*5){
                        bodyText =  request.charset() != null
                                ? new String(request.body(), request.charset())
                                : null;
                    }else{
                        bodyText = " to large";
                    }
                    log(request.httpMethod().name()+":"+request.url(), "req:%s",bodyText != null ? bodyText : "Binary data");
                }
            }
        }
    }

    @Override
    protected Response logAndRebufferResponse(String configKey,
                                              Level logLevel,
                                              Response response,
                                              long elapsedTime)
            throws IOException {
        if (logger.isDebugEnabled()) {
            return feignLogAndRebufferResponse(configKey, logLevel, response, elapsedTime);
        }
        return response;
    }

    private Response feignLogAndRebufferResponse(String configKey, Level logLevel, Response response, long elapsedTime) throws IOException {
        int status = response.status();
        if (logLevel.ordinal() == Level.FULL.ordinal()) {
            int bodyLength = 0;
            if (response.body() != null && !(status == 204 || status == 205)) {
                byte[] bodyData = Util.toByteArray(response.body().asInputStream());
                bodyLength = bodyData.length;
                if (bodyLength > 0) {
                    String respStr = StringUtil.EMPTY;
                    if(bodyLength < 1024*1024*5){
                        respStr = decodeOrDefault(bodyData, UTF_8, "Binary data");
                    }else{
                        respStr = " to large";
                    }
                    log(response.request().httpMethod().name()+":"+response.request().url(), "costTimes:%sms,resp:%s",elapsedTime,respStr);
                }
                return response.toBuilder().body(bodyData).build();
            }
        }
        return response;
    }

    @Override
    protected void log(String url, String format, Object... args) {
        if (logger.isDebugEnabled()) {
            logger.debug(String.format(url + "," + format, args));
        }
    }
}
